package edu.pku.taas.hyperic.types2;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.hqapi1.AgentApi;
import org.hyperic.hq.hqapi1.ResourceApi;
import org.hyperic.hq.hqapi1.XmlUtil;
import org.hyperic.hq.hqapi1.types.AgentResponse;
import org.hyperic.hq.hqapi1.types.PingAgentResponse;
import org.hyperic.hq.hqapi1.types.Resource;
import org.hyperic.hq.hqapi1.types.ResourcesResponse;
import org.hyperic.hq.hqapi1.types.ResponseStatus;

import com.thoughtworks.xstream.XStream;

import edu.pku.taas.hyperic.monitor.HQApiHelper;
import edu.pku.taas.hyperic.monitor.LogConfigure;
import edu.pku.taas.hyperic.monitor.MonitorServerConfigureManager;
import edu.pku.taas.hyperic.monitor.MonitorConstants;

public class CopyOfResourceTree {
	private static List MONITOR_PROTOTYPE_LIST = new ArrayList();
	private static List OS_TYPE_LIST = new ArrayList();
	private static org.hyperic.hq.hqapi1.types.Agent _localAgent = null;
	private static Log log = LogFactory.getLog(CopyOfResourceTree.class);

	private Map<String, Object> ip2ClusterMap = new HashMap<String, Object>();
	private Map<String, PhysicalMachine> ip2PhysicalMachineMap = new HashMap<String, PhysicalMachine>();
	private Map<String, Object> ip2VirtualMachineMap = new HashMap<String, Object>();

	private Map<String, PhysicalMachine> name2PhysicalMachineMap = new HashMap<String, PhysicalMachine>();
	private Map<String, Object> name2VirtualMachineMap = new HashMap<String, Object>();

	private Map<String, Object> id2ClusterMap = new HashMap<String, Object>();
	private Map<String, Object> id2PhysicalMachineMap = new HashMap<String, Object>();
	private Map<String, Object> id2VirtualMachineMap = new HashMap<String, Object>();

	private Map<String, String> vmip2HostIPPool = new HashMap<String, String>();

	private Map<String, String> pmip2HostName = new HashMap<String, String>();

	private Map<String, List<Resource>> hostIp2VMResourceEntryPool = new HashMap<String, List<Resource>>();
	private Cloud cloud;

	private XenManager xm = new XenManager();

	protected Log getLog() {
		return log;
	}

	// TODO: use Liu's API get vms
	private void queryAllVMsInCloud() {
		int clusterNum = MonitorServerConfigureManager.getIntConfigure(MonitorConstants.CLUSTER_NUM);

		for (int i = 1; i <= clusterNum; i++) {

			String clusterMasterIP = MonitorServerConfigureManager.getStringConfigure(MonitorConstants.CLUSTER_MASTER_IP
					+ MonitorConstants.CLUSTER_CONF_SUFFIX + i);
			String clusterMasterHostName = MonitorServerConfigureManager.getStringConfigure(MonitorConstants.CLUSTER_MASTER_HOST_NAME
					+ MonitorConstants.CLUSTER_CONF_SUFFIX + i);

			List<Object> vmList = new ArrayList();// getVMIPListInCluster();
			for (Object ip : vmList) {
				String vmIP = null;
				String hostIP = null;
				vmip2HostIPPool.put(vmIP, hostIP);
			}

			vmip2HostIPPool.put("172.16.0.67", "172.16.0.201");
			vmip2HostIPPool.put("172.16.0.74", "172.16.0.201");
			vmip2HostIPPool.put("172.16.0.65", "172.16.0.201");
		}
	}

	private List<String> getVMIPListInCluster() {
		// TODO Auto-generated method stub
		return null;
	}

	public CopyOfResourceTree() {
		LogConfigure.setUp();
		log.info("common log set up ok");

		int[] monitorTypes = { 10113, 10126, 10131, 10132, 10141, 10142, 10159, 10316, 10341, 10415, 10424 };
		// removed :10125--network server; 10124--process server;10143 xen vm
		// hostserver:removed vm metrics:10146 Xen Host
		// CPU;10145;10148,10147,10144
		for (int i : monitorTypes)
			MONITOR_PROTOTYPE_LIST.add(i);

		int[] osTypes = { 10113, 10141 };
		for (int i : osTypes)
			OS_TYPE_LIST.add(i);

		queryAllVMsInCloud();
		createCloud();
	}

	private void createCloud() {
		cloud = new Cloud();
		cloud.setMasterIP(MonitorServerConfigureManager.getStringConfigure(MonitorConstants.CLOUD_MASTER_IP));
		cloud.setMasterName(MonitorServerConfigureManager.getStringConfigure(MonitorConstants.CLOUD_MASTER_HOST_NAME));
		createClusters();
	}

	public Cloud getCloud() {
		return cloud;
	}

	private void createClusters() {
		List<Cluster> clusters = new ArrayList<Cluster>();
		cloud.setClusters(clusters);
		int clusterNum = MonitorServerConfigureManager.getIntConfigure(MonitorConstants.CLUSTER_NUM);

		for (int i = 1; i <= clusterNum; i++) {
			Cluster cluster = new Cluster();

			String clusterMasterIP = MonitorServerConfigureManager.getStringConfigure(MonitorConstants.CLUSTER_MASTER_IP
					+ MonitorConstants.CLUSTER_CONF_SUFFIX + i);
			String clusterMasterHostName = MonitorServerConfigureManager.getStringConfigure(MonitorConstants.CLUSTER_MASTER_HOST_NAME
					+ MonitorConstants.CLUSTER_CONF_SUFFIX + i);
			int clusterMasterPort = MonitorServerConfigureManager.getIntConfigure(MonitorConstants.CLUSTER_MASTER_PORT
					+ MonitorConstants.CLUSTER_CONF_SUFFIX + i);
			cluster.setMasterHostName(clusterMasterHostName);
			cluster.setMasterIP(clusterMasterIP);
			System.out.println("clusterMasterHostName=" + clusterMasterHostName);
			System.out.println("clusterMasterIP=" + clusterMasterIP);
			System.out.println("clusterMasterPort=" + clusterMasterPort);
			cluster.setMasterPort(clusterMasterPort);

			ip2ClusterMap.put(cluster.getMasterIP(), cluster);

			try {
				createClusterStructure(cluster);
				// createVirtualMachines();
			} catch (Exception e) {
				log.error("create cluster error: cluster ip=" + cluster.getMasterIP());
				e.printStackTrace();
			}

			clusters.add(cluster);
		}

	}

	private void createClusterStructure(Cluster cluster) throws Exception {
		List<PhysicalMachine> physicalMachines = createPhysicalMachines(cluster);
		cluster.setPhysicalMachines(physicalMachines);
	}

	private org.hyperic.hq.hqapi1.types.Agent getClusterAgent(Cluster cluster) throws IOException, Exception {
		String clusterMasterIp = cluster.getMasterIP();
		int clusterMasterPort = cluster.getMasterPort();
		System.out.println("clusterMasterIp:" + clusterMasterIp);
		System.out.println("clusterMasterPort:" + clusterMasterPort);
		AgentApi api = HQApiHelper.getApi().getAgentApi();

		AgentResponse response = api.getAgent(clusterMasterIp, clusterMasterPort);
		org.hyperic.hq.hqapi1.types.Agent agent = response.getAgent();

		System.out.println();
		// XmlUtil.serialize(response, System.out, true);
		System.out.println();
		if (response.getStatus().equals(ResponseStatus.FAILURE)) {
			String err = "Error querying agents: " + response.getError().getReasonText();
			log.error(err);
			throw new Exception(err);
		}

		System.out.println("begin to print resource:");

		PingAgentResponse pingRespnse = api.pingAgent(agent);
		boolean isUp = pingRespnse.getStatus().equals(ResponseStatus.SUCCESS) && pingRespnse.isUp();
		System.out.println("#resource on agent id=" + agent.getId() + "  ip=" + agent.getAddress() + " port=" + agent.getPort()
				+ " is up? " + isUp);
		return agent;
	}

	private List<PhysicalMachine> createPhysicalMachines(Cluster cluster) throws Exception {
		List<PhysicalMachine> pml = new ArrayList<PhysicalMachine>();

		List<String> pmIpList = getClusterPhysicalMachineIPList(cluster.getMasterIP());
		int pmPort = MonitorServerConfigureManager.getIntConfigure(MonitorConstants.HQ_MONITOR_AGENT_PORT);
		for (String ip : pmIpList) {

			AgentApi agentApi = HQApiHelper.getApi().getAgentApi();
			AgentResponse response = agentApi.getAgent(ip, pmPort);
			org.hyperic.hq.hqapi1.types.Agent agent = response.getAgent();

			ResourceApi api = HQApiHelper.getApi().getResourceApi();
			ResourcesResponse findResponse = api.getResources(agent, false, true);
			XmlUtil.serialize(findResponse, System.out, true);

			System.out.println("----------------");
			System.out.println("Found getResource: " + findResponse.getResource().size());
			System.out.println("----------------");
			List<org.hyperic.hq.hqapi1.types.Resource> hqResourceList = findResponse.getResource();

			if (hqResourceList.size() == 2) {
				PhysicalMachine pm = null;
				String pmName = null;
				for (Resource r : hqResourceList) {
					if (r.getResourcePrototype().getId() != MonitorConstants.XEN_HOST_TYPE) {
						pmName = r.getName();
					}
				}

				for (Resource r : hqResourceList) {
					if (r.getResourcePrototype().getId() == MonitorConstants.XEN_HOST_TYPE) {
						pm = createXenServer(hqResourceList.get(0),pmName);
						pml.add(pm);
					}
				}

				// for(Resource r :hqResourceList){
				// if(r.getResourcePrototype().getId()!=MonitorConstants.XEN_HOST_TYPE){
				// List<MonitorableResource> mrl =
				// createMonitorableResources(r.getResource());
				// pm.getMonitorableResources().addAll(mrl);
				// }
				// }
			}else if (hqResourceList.size() == 1) {
				PhysicalMachine p = createPhysicalMachine(hqResourceList.get(0));
				pml.add(p);
			} 

		}

		return pml;

	}

	private PhysicalMachine createXenServer(Resource hqr, String pmName) {
		PhysicalMachine xenServerPM = new PhysicalMachine();

		String ip = getHostIP(hqr);
		int id = hqr.getId();
		System.out.println("name===================" + pmName);
		MachineInfo mi = getMachineInfo(pmName);
		String uuid = mi.getUuid();
		xenServerPM.setUuid(uuid);
		
		xenServerPM.setAgentId(hqr.getAgent().getId());
		xenServerPM.setAgentPort(hqr.getAgent().getPort());

		xenServerPM.setIp(ip);
		xenServerPM.setName(pmName);

		xenServerPM.setResourceId(hqr.getId());
		xenServerPM.setXenHost(true);

		xenServerPM.setDescription(hqr.getDescription());

		xenServerPM.setResourcePrototypeId(hqr.getResourcePrototype().getId());
		xenServerPM.setResourcePrototypeName(hqr.getResourcePrototype().getName());
		xenServerPM.setResourceType(MonitorConstants.RESOURCE_XENSERVER_TYPE);

		// List<MonitorableResource> mrl =
		// createMonitorableResources(hqr.getResource());
		// xenServerPM.setMonitorableResources(mrl);

		xenServerPM.setVms(createVirtualMachines(hqr.getResource()));

		ip2PhysicalMachineMap.put(ip, xenServerPM);
		id2PhysicalMachineMap.put("" + id, xenServerPM);
		System.out.println("ctreate pm=======" + xenServerPM);

		return xenServerPM;
	}

	private List<VirtualMachine> createVirtualMachines(List<Resource> vmrl) {

		List<VirtualMachine> vml = new ArrayList<VirtualMachine>();
		for (Resource vmr : vmrl) {
			if (vmr.getResourcePrototype().getId() != MonitorConstants.XEN_VM_SERVER_TYPE) {
				vml.add(converVirtualMachine(vmr));
			}
		}

		return vml;
	}

	private MachineInfo getMachineInfo(String vmrName) {
		return xm.getMachineInfo(vmrName);
	}

	public VirtualMachine converVirtualMachine(Resource vmr) {
		VirtualMachine vm = new VirtualMachine();
		String name = vmr.getName();

		MachineInfo mi = getMachineInfo(name);
		String ip = mi.getIp();
		String uuid = mi.getUuid();

		vm.setDescription(vmr.getDescription());
		vm.setId(vmr.getId());
		vm.setName(name);
		vm.setIp(ip);
		vm.setUuid(uuid);
		vm.setResourcePrototypeId(vmr.getResourcePrototype().getId());
		vm.setResourcePrototypeName(vmr.getResourcePrototype().getName());

		/**
		 * there isn't any MonitorableResource in Xen vm so far
		 */
		// List<MonitorableResource> mrl =
		// createMonitorableResources(vmr.getResource());
		// vm.setMonitorableResources(mrl);

		System.out.println("ctreate vm=======" + vm);
		return vm;
	}

	private List<String> getClusterPhysicalMachineIPList(String clusterMasterIP) {
		List<Map.Entry<String, String>> cl = MonitorServerConfigureManager.getConfigureList();

		List<String> pmIpList = new ArrayList<String>();
		String physicalMachinePrefix = "cloud.clusters.";
		String physicalMachineSufix = ".physicalmachine.";

		String physcalMachineConf = physicalMachinePrefix + clusterMasterIP + physicalMachineSufix;

		for (Map.Entry<String, String> c : cl) {
			String k = c.getKey();
			String v = c.getValue();
			System.out.println("MapEntry:" + c);
			if (k.startsWith(physcalMachineConf)) {
				pmIpList.add(v);
				System.out.println(clusterMasterIP + " get pm ip in cluster:" + c);
			}

		}

		return pmIpList;
	}

	private PhysicalMachine createPhysicalMachine(org.hyperic.hq.hqapi1.types.Resource hqr) {
		PhysicalMachine pm = new PhysicalMachine();

		String name = hqr.getName();
		String ip = getHostIP(hqr);
		int id = hqr.getId();

		MachineInfo mi = getMachineInfo(name);
		String uuid = mi.getUuid();
		pm.setUuid(uuid);

		pm.setIp(ip);
		pm.setName(name);

		pm.setAgentId(hqr.getAgent().getId());
		pm.setAgentPort(hqr.getAgent().getPort());
		
		pm.setResourceId(hqr.getId());
		pm.setXenHost(false);

		pm.setDescription(hqr.getDescription());

		pm.setResourcePrototypeId(hqr.getResourcePrototype().getId());
		pm.setResourcePrototypeName(hqr.getResourcePrototype().getName());

		pm.setResourceType(MonitorConstants.RESOURCE_PHYSICAL_MACHINE_TYPE);

		ip2PhysicalMachineMap.put(ip, pm);
		id2PhysicalMachineMap.put("" + id, pm);
		System.out.println("ctreate pm=======" + pm);

		return pm;
	}

	// private PhysicalMachine
	// createPhysicalMachine(org.hyperic.hq.hqapi1.types.Resource hqr) {
	//
	// PhysicalMachine pm = new PhysicalMachine();
	// pm.setAgentId(hqr.getAgent().getId());
	// pm.setAgentPort(hqr.getAgent().getPort());
	// pm.setDescription(hqr.getDescription());
	// String hostIp =null;
	// hostIp = getHostIP(hqr);
	//		
	//
	// pm.setIp(hostIp);
	// pm.setName(hqr.getName());
	// pm.setResourceId(hqr.getId());
	//
	// pm.setResourcePrototypeId(hqr.getResourcePrototype().getId());
	// pm.setResourcePrototypeName(hqr.getResourcePrototype().getName());
	//		
	// // List<MonitorableResource> mrl =
	// createMonitorableResources(hqr.getResource());
	// // pm.setMonitorableResources(mrl);
	// System.out.println("ctreate pm=======" + pm);
	// ip2PhysicalMachineMap.put(hostIp, pm);
	//
	// return pm;
	// }

	private String getHostIP(org.hyperic.hq.hqapi1.types.Resource hqr) {
		String hostIp = null;
		for (org.hyperic.hq.hqapi1.types.Ip ip : hqr.getIp()) {
			if (!"127.0.0.1".equals(ip.getAddress())) {
				hostIp = ip.getAddress();

				break;
			}
		}
		return hostIp;
	}

	// private void createVirtualMachine(PhysicalMachine pm, Resource vmr) {
	//
	// List<VirtualMachine> vml = pm.getVms();
	// if (vml == null) {
	// vml = new ArrayList<VirtualMachine>();
	// }
	//
	// VirtualMachine vm =
	// HQType2MonitorTypeConvertHelper.converVirtualMachine(vmr);
	//
	// // List<MonitorableResource> mrl =
	// createMonitorableResources(vmr.getResource());
	// // vm.setMonitorableResources(mrl);
	//
	// vml.add(vm);
	// System.out.println("ctreate vm=======" + vm);
	// }

	// private List<MonitorableResource>
	// createMonitorableResources(List<Resource> rl) {
	// List<MonitorableResource> mrl = new ArrayList<MonitorableResource>();
	// for (Resource r : rl) {
	// int resourcePrototype = r.getResourcePrototype().getId();
	// if (isInTheMonitorTypeList(resourcePrototype)) {
	// MonitorableResource mr = new MonitorableResource();
	//
	// mr.setDescription(r.getDescription());
	// mr.setId(r.getId());
	// mr.setName(r.getName());
	// mr.setResourcePrototypeId(r.getResourcePrototype().getId());
	// mr.setResourcePrototypeName(r.getResourcePrototype().getName());
	// mrl.add(mr);
	// } else {
	// List<MonitorableResource> mrl2 =
	// createMonitorableResources(r.getResource());
	// if (!mrl2.isEmpty())
	// mrl.addAll(mrl2);
	// }
	//
	// }
	// return mrl;
	// }

	public Cloud getCloudRoot() {
		return cloud;
	}

	private boolean isInTheMonitorTypeList(int typeId) {
		return MONITOR_PROTOTYPE_LIST.contains(typeId);
	}

	private boolean isInTheOSTypeList(int typeId) {
		return OS_TYPE_LIST.contains(typeId);
	}

	/**
	 * Get the locally running agent.
	 * 
	 * @return The locally running agent or null if one does not exist.
	 * @throws Exception
	 *             If a running agent could not be found.
	 */

	public static void main(String[] args) throws Exception {

		XStream xstream = new XStream();
		xstream.alias("Cloud", Cloud.class);
		xstream.alias("Cluster", Cluster.class);
		xstream.alias("PhysicalMachine", PhysicalMachine.class);
		xstream.alias("MonitorableResource", MonitorableResource.class);
		xstream.alias("VirtualMachine", VirtualMachine.class);

		xstream.aliasAttribute(Cloud.class, "masterIP", "masterIP");
		xstream.aliasAttribute(Cloud.class, "masterHostName", "masterHostName");

		xstream.aliasAttribute(Cluster.class, "masterIP", "masterIP");
		xstream.aliasAttribute(Cluster.class, "masterHostName", "masterHostName");
		xstream.aliasAttribute(Cluster.class, "masterPort", "masterPort");

		xstream.aliasAttribute(PhysicalMachine.class, "resourceId", "resourceId");
		xstream.aliasAttribute(PhysicalMachine.class, "name", "name");
		xstream.aliasAttribute(PhysicalMachine.class, "description", "description");
		xstream.aliasAttribute(PhysicalMachine.class, "isXenHost", "isXenHost");
		xstream.aliasAttribute(PhysicalMachine.class, "ip", "ip");

		xstream.aliasAttribute(VirtualMachine.class, "id", "id");
		xstream.aliasAttribute(VirtualMachine.class, "name", "name");
		xstream.aliasAttribute(VirtualMachine.class, "ip", "ip");
		xstream.aliasAttribute(VirtualMachine.class, "description", "description");

		xstream.aliasAttribute(MonitorableResource.class, "id", "id");
		xstream.aliasAttribute(MonitorableResource.class, "name", "name");
		xstream.aliasAttribute(MonitorableResource.class, "description", "description");

		CopyOfResourceTree rt = new CopyOfResourceTree();
		Cloud cloud = rt.getCloud();

		System.out.println(xstream.toXML(cloud));

	}

}
